Skip to content

Automated Test: notification-rule-enhancements #336

Conversation

admin-coderabbit
Copy link
Owner

@admin-coderabbit admin-coderabbit commented Feb 4, 2026

This pull request was automatically created by @coderabbitai/e2e-reviewer.

Batch created pull request.

Summary by CodeRabbit

  • New Features

    • Added support for Grafana Prometheus rule permissions and access control checks alongside existing ruler-based permissions.
    • Enhanced rule action visibility based on granular permission checks for pause, delete, duplicate, silence, and export actions.
  • Bug Fixes

    • Simplified rule group loading to use a single data source, improving consistency and reliability.
  • Refactoring

    • Consolidated permission queries to reduce API calls per rule source.
    • Optimized rule list rendering logic for Grafana-managed rules.

* wip

* Add working actions for GMA rules based on Prom-only API

* Remove Ruler-loader related code for Grafana rules

Co-authored-by: Sonia Augilar <sonia.aguilar@grafana.com>

* Remove outdated tests

* add some comments

* remove commented code

* remove showLocation property

* Add missing mocks in tests

* Add showLocation to GrafanaRuleListItem, improve useAbilities, address PR feedback

* Enhance GrafanaGroupLoader tests: Add permission checks and More button functionality

- Introduced user permission grants for alerting actions in tests.
- Added tests for rendering the More button with action menu options.
- Verified that each rule has its own action buttons and handles permissions correctly.
- Ensured the edit button is not rendered when user lacks edit permissions.
- Confirmed the correct menu actions are displayed when the More button is clicked.

* Update translations

---------

Co-authored-by: Sonia Aguilar <soniaaguilarpeiron@gmail.com>
Co-authored-by: Sonia Augilar <sonia.aguilar@grafana.com>
@coderabbit-eval
Copy link

coderabbit-eval bot commented Feb 4, 2026

📝 Walkthrough

Walkthrough

This PR introduces Grafana Prometheus rule support to the alerting system by adding grouped ability/permission hooks, refactoring components to use batched permission checks, and simplifying Grafana rule list loading to rely exclusively on Prometheus data. The changes add new hooks for querying multiple Grafana rule permissions, update existing components to use these hooks, and introduce a new GrafanaRuleListItem component for rule rendering.

Changes

Cohort / File(s) Summary
Ability Hooks for Grafana Rules
useAbilities.ts
Added new hooks (useAllGrafanaPromRuleAbilities, useGrafanaPromRuleAbility, useGrafanaPromRuleAbilities, useIsGrafanaPromRuleEditable) to handle Grafana-managed rule permissions. Introduced skipToken mechanism for conditional rule lookups. Extended existing hooks to support undefined rules and Grafana context. Updated permission resolution to use groupIdentifier-based origin detection.
Component Ability Check Refactoring
AlertRuleMenu.tsx, RuleActionsButtons.V2.tsx
Refactored from individual per-action ability checks to grouped ability hooks for improved performance. RuleActionsButtons.V2 now accepts optional rule or promRule and computes combined edit/provision capabilities from both Ruler and Grafana sources. Added multi-source identifier resolution with graceful error handling.
Grafana Rule List Rendering
GrafanaGroupLoader.tsx, GrafanaRuleListItem.tsx, FilterView.tsx
Removed Ruler-based rule matching logic and related exports (matchRules, MatchingResult). GrafanaGroupLoader now sources rules from Prometheus only. Introduced new GrafanaRuleListItem component for type-aware rule rendering (alerting, recording, unknown). FilterView now uses GrafanaRuleListItem instead of GrafanaRuleLoader.
Rule List Item Cleanup
GrafanaRuleLoader.tsx
Deleted module containing deprecated GrafanaRuleLoader and related GrafanaRuleListItem. Functionality replaced by new standalone GrafanaRuleListItem component in separate file.
Test Coverage Updates
RulesTable.test.tsx, GrafanaGroupLoader.test.tsx, RuleDetails.test.tsx
Expanded mocking to include new grouped ability hooks (useGrafanaPromRuleAbilities, useRulerRuleAbilities). Added permission-driven test scenarios for action visibility. Updated Cloud rule test data to use mimir-backed rulesSource. Added extensive tests for menu items, edit links, and permission-based button visibility.
Data Model & Utilities
unified-alerting-dto.ts, rules.ts, prometheusGroupsGenerator.ts, grafana.json
Added optional provenance property to GrafanaPromRuleDTOBase. Added isProvisionedPromRule() utility for PromRuleDTO provisioning checks. Removed GrafanaRulerGroup prefetch from cache population. Removed two localization entries for missing rule details errors.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 Hops of logic, bundled tight,
Grafana rules now render right,
Abilities grouped, permissions found,
Simplified paths, no Ruler-bound!
Faster checks, cleaner code—
Alerting takes a lighter load!

🚥 Pre-merge checks | ✅ 1 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Title check ⚠️ Warning The title 'Automated Test: notification-rule-enhancements' does not accurately describe the actual changes, which involve refactoring ability checks, adding Grafana Prometheus rule support, and restructuring rule list components. Revise the title to reflect the main technical changes, such as 'Refactor rule abilities to support Grafana Prometheus rules' or 'Add grouped ability checks and Grafana Prom rule support'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch notification-rule-enhancements

Comment @coderabbit eval help to get the list of available commands and usage tips.

@coderabbit-eval coderabbit-eval bot closed this Feb 4, 2026
Copy link

@coderabbit-eval coderabbit-eval bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@public/app/features/alerting/unified/hooks/useAbilities.ts`:
- Around line 287-334: The hook useAllGrafanaPromRuleAbilities must return
NotSupported for all actions when rule is undefined (skipToken); inside the
useMemo in useAllGrafanaPromRuleAbilities, add an early guard like if (!rule) {
return an Abilities<AlertRuleAction> object where every AlertRuleAction maps to
NotSupported } so
MaybeSupported/MaybeSupportedUnlessImmutable/duplicateSupported are not allowed
to default to AlwaysSupported and accidentally enable actions for non-Grafana
rules; update the returned abilities to use NotSupported for Duplicate, View,
Update, Delete, Explore, Silence, ModifyExport, Pause, Restore,
DeletePermanently when rule is missing.

In `@public/app/features/alerting/unified/rule-list/FilterView.tsx`:
- Around line 157-163: The GrafanaRuleListItem rendered inside the .map() loop
is missing a stable key prop which can cause React list rendering issues; update
the GrafanaRuleListItem JSX to include key={key}, matching the other branches
(DataSourceRuleLoader and UnknownRuleListItem) that already use the key variable
from the map destructuring so each item has a stable identifier.
🧹 Nitpick comments (2)
public/app/features/alerting/unified/rule-list/GrafanaGroupLoader.test.tsx (1)

36-43: Unused delete menu item selector.

The ui.menuItems.delete() selector is defined here but never used in any test assertions. Meanwhile, the test at line 207 expects exactly 4 menu items, which aligns with the 4 items actually asserted (silence, copyLink, duplicate, export).

Either:

  1. Remove the unused delete selector if the delete action isn't expected in this menu
  2. Add test coverage for the delete action if it should appear when AlertingRuleDelete permission is granted
public/app/features/alerting/unified/rule-list/GrafanaGroupLoader.tsx (1)

24-28: Stale documentation comment.

The JSDoc comment states "Loads an evaluation group from Prometheus and Ruler endpoints" but the implementation now only queries Prometheus. The Ruler-based matching logic has been removed per the AI summary.

📝 Suggested documentation update
 /**
- * Loads an evaluation group from Prometheus and Ruler endpoints.
+ * Loads an evaluation group from the Prometheus endpoint.
  * Displays a loading skeleton while the data is being fetched.
  * Polls the Prometheus endpoint every 20 seconds to refresh the data.
  */

Comment on lines +287 to +334
export function useAllGrafanaPromRuleAbilities(rule: GrafanaPromRuleDTO | undefined): Abilities<AlertRuleAction> {
// For GrafanaPromRuleDTO, we use useIsGrafanaPromRuleEditable instead
const { isEditable, isRemovable, loading } = useIsGrafanaPromRuleEditable(rule); // duplicate
const [_, exportAllowed] = useAlertingAbility(AlertingAction.ExportGrafanaManagedRules);
const canSilence = useCanSilence(rule);

const silenceSupported = useGrafanaRulesSilenceSupport();
const canSilenceInFolder = useCanSilenceInFolder(rule?.folderUid);

const abilities = useMemo<Abilities<AlertRuleAction>>(() => {
const isProvisioned = rulerRuleType.grafana.rule(rule) && Boolean(rule.grafana_alert.provenance);
// const isFederated = isFederatedRuleGroup();
const isProvisioned = rule ? isProvisionedPromRule(rule) : false;

// Note: Grafana managed rules can't be federated - this is strictly a Mimir feature
// See: https://grafana.com/docs/mimir/latest/references/architecture/components/ruler/#federated-rule-groups
const isFederated = false;
const isGrafanaManagedAlertRule = rulerRuleType.grafana.rule(rule);
// All GrafanaPromRuleDTO rules are Grafana-managed by definition
const isAlertingRule = prometheusRuleType.grafana.alertingRule(rule);
const isPluginProvided = isPluginProvidedRule(rule);

// if a rule is either provisioned, federated or provided by a plugin rule, we don't allow it to be removed or edited
const immutableRule = isProvisioned || isFederated || isPluginProvided;

// while we gather info, pretend it's not supported
const MaybeSupported = loading ? NotSupported : isRulerAvailable;
// GrafanaPromRuleDTO rules are always supported (no loading state for ruler availability)
const MaybeSupported = loading ? NotSupported : AlwaysSupported;
const MaybeSupportedUnlessImmutable = immutableRule ? NotSupported : MaybeSupported;

// Creating duplicates of plugin-provided rules does not seem to make a lot of sense
const duplicateSupported = isPluginProvided ? NotSupported : MaybeSupported;

const rulesPermissions = getRulesPermissions(rulesSourceName);
const rulesPermissions = getRulesPermissions('grafana');

const abilities: Abilities<AlertRuleAction> = {
[AlertRuleAction.Duplicate]: toAbility(duplicateSupported, rulesPermissions.create),
[AlertRuleAction.View]: toAbility(AlwaysSupported, rulesPermissions.read),
[AlertRuleAction.Update]: [MaybeSupportedUnlessImmutable, isEditable ?? false],
[AlertRuleAction.Delete]: [MaybeSupportedUnlessImmutable, isRemovable ?? false],
[AlertRuleAction.Explore]: toAbility(AlwaysSupported, AccessControlAction.DataSourcesExplore),
[AlertRuleAction.Silence]: canSilence,
[AlertRuleAction.ModifyExport]: [isGrafanaManagedAlertRule, exportAllowed],
[AlertRuleAction.Pause]: [MaybeSupportedUnlessImmutable && isGrafanaManagedAlertRule, isEditable ?? false],
[AlertRuleAction.Restore]: [MaybeSupportedUnlessImmutable && isGrafanaManagedAlertRule, isEditable ?? false],
[AlertRuleAction.Silence]: [silenceSupported, canSilenceInFolder && isAlertingRule],
[AlertRuleAction.ModifyExport]: [isAlertingRule, exportAllowed],
[AlertRuleAction.Pause]: [MaybeSupportedUnlessImmutable && isAlertingRule, isEditable ?? false],
[AlertRuleAction.Restore]: [MaybeSupportedUnlessImmutable && isAlertingRule, isEditable ?? false],
[AlertRuleAction.DeletePermanently]: [
MaybeSupportedUnlessImmutable && isGrafanaManagedAlertRule,
MaybeSupportedUnlessImmutable && isAlertingRule,
(isRemovable && isAdmin()) ?? false,
],
};

return abilities;
}, [rule, loading, isRulerAvailable, rulesSourceName, isEditable, isRemovable, canSilence, exportAllowed]);
}, [rule, loading, isEditable, isRemovable, canSilenceInFolder, exportAllowed, silenceSupported]);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Ensure skipToken results in “not supported” abilities.

When skipToken is used, rule becomes undefined, but MaybeSupported currently defaults to AlwaysSupported, which can enable actions (e.g., Duplicate) for non‑Grafana rules. Consider short‑circuiting to all‑NotSupported when rule is undefined.

🛠️ Suggested guard
 export function useAllGrafanaPromRuleAbilities(rule: GrafanaPromRuleDTO | undefined): Abilities<AlertRuleAction> {
   // For GrafanaPromRuleDTO, we use useIsGrafanaPromRuleEditable instead
   const { isEditable, isRemovable, loading } = useIsGrafanaPromRuleEditable(rule); // duplicate
   const [_, exportAllowed] = useAlertingAbility(AlertingAction.ExportGrafanaManagedRules);

   const silenceSupported = useGrafanaRulesSilenceSupport();
   const canSilenceInFolder = useCanSilenceInFolder(rule?.folderUid);
+
+  if (!rule) {
+    return {
+      [AlertRuleAction.Duplicate]: [NotSupported, false],
+      [AlertRuleAction.View]: [NotSupported, false],
+      [AlertRuleAction.Update]: [NotSupported, false],
+      [AlertRuleAction.Delete]: [NotSupported, false],
+      [AlertRuleAction.Explore]: [NotSupported, false],
+      [AlertRuleAction.Silence]: [NotSupported, false],
+      [AlertRuleAction.ModifyExport]: [NotSupported, false],
+      [AlertRuleAction.Pause]: [NotSupported, false],
+      [AlertRuleAction.Restore]: [NotSupported, false],
+      [AlertRuleAction.DeletePermanently]: [NotSupported, false],
+    };
+  }

Also applies to: 380-405

🤖 Prompt for AI Agents
In `@public/app/features/alerting/unified/hooks/useAbilities.ts` around lines 287
- 334, The hook useAllGrafanaPromRuleAbilities must return NotSupported for all
actions when rule is undefined (skipToken); inside the useMemo in
useAllGrafanaPromRuleAbilities, add an early guard like if (!rule) { return an
Abilities<AlertRuleAction> object where every AlertRuleAction maps to
NotSupported } so
MaybeSupported/MaybeSupportedUnlessImmutable/duplicateSupported are not allowed
to default to AlwaysSupported and accidentally enable actions for non-Grafana
rules; update the returned abilities to use NotSupported for Duplicate, View,
Update, Delete, Explore, Silence, ModifyExport, Pause, Restore,
DeletePermanently when rule is missing.

Comment on lines +157 to 163
<GrafanaRuleListItem
rule={rule}
groupIdentifier={groupIdentifier}
namespaceName={ruleWithOrigin.namespaceName}
showLocation={true}
/>
);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cd /tmp && find . -name "FilterView.tsx" -path "*/alerting/unified/rule-list/*" 2>/dev/null | head -5

Repository: admin-coderabbit/coderabbit-grafana-mirror

Length of output: 68


🏁 Script executed:

cat -n "public/app/features/alerting/unified/rule-list/FilterView.tsx" | sed -n '140,175p'

Repository: admin-coderabbit/coderabbit-grafana-mirror

Length of output: 1689


Add a stable key for GrafanaRuleListItem list items.

GrafanaRuleListItem is rendered inside a .map() loop (line 151) and lacks a key prop, while the other components in the same switch statement (DataSourceRuleLoader on line 165 and UnknownRuleListItem on line 169) include key={key}. The key variable is available in scope from the destructuring on line 152.

✅ Suggested fix
              return (
                <GrafanaRuleListItem
+                 key={key}
                  rule={rule}
                  groupIdentifier={groupIdentifier}
                  namespaceName={ruleWithOrigin.namespaceName}
                  showLocation={true}
                />
              );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<GrafanaRuleListItem
rule={rule}
groupIdentifier={groupIdentifier}
namespaceName={ruleWithOrigin.namespaceName}
showLocation={true}
/>
);
<GrafanaRuleListItem
key={key}
rule={rule}
groupIdentifier={groupIdentifier}
namespaceName={ruleWithOrigin.namespaceName}
showLocation={true}
/>
);
🧰 Tools
🪛 Biome (2.3.13)

[error] 157-163: Missing key property for this element in iterable.

The order of the items may change, and having a key can help React identify which item was moved.
Check the React documentation.

(lint/correctness/useJsxKeyInIterable)

🤖 Prompt for AI Agents
In `@public/app/features/alerting/unified/rule-list/FilterView.tsx` around lines
157 - 163, The GrafanaRuleListItem rendered inside the .map() loop is missing a
stable key prop which can cause React list rendering issues; update the
GrafanaRuleListItem JSX to include key={key}, matching the other branches
(DataSourceRuleLoader and UnknownRuleListItem) that already use the key variable
from the map destructuring so each item has a stable identifier.

Sign in to join this conversation on GitHub.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

1 participant